/*
 *
 *  AutoWallpaper (Android) Version 1.x
 *  Copyright (C) 2010 - 2011, Tyler H. Jones (me@tylerjones.me)
 *  http://www.autowallpaper.org/
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */


package com.tylerhjones.autowallpaper;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.app.WallpaperManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Binder;
import android.os.IBinder;
import android.util.DisplayMetrics;
import android.util.Log;
import com.tylerhjones.autowallpaper.AWCore;

public class AWService extends Service {
	private static final String TAG = "AWService"; //Tag for Log messages
	private final IBinder mBinder = new LocalBinder();
	
	//Timer variables
	private int tickCount = 0;
	private static Timer timer = new Timer();

	private NotificationManager mNManager;
	private WallpaperManager WM;
	
	private AWCore Core; //Declare AWCore instance
	//private Common COM = new Common(); //Declare Common instance
	
	public void onCreate() {
		super.onCreate();
		Log.d(TAG, "onCreate: Beginning...");
		Core = new AWCore(this); //Create AWCore class instance
		
		//Declare broadcast receiver that triggers when the lock screen is unlocked
		BroadcastReceiver xcvrUnlockScreen = new BroadcastReceiver() {
			  @Override
			  public void onReceive(Context context, Intent intent) {
			    if (intent.getAction().equals(Intent.ACTION_USER_PRESENT)) {
		    		Log.v(TAG, "Screen unlocked!");
			    	if(Core.getTimerInterval() == Common.INTERVAL_UNLOCK && Core.getAutoChange() && Core.getNumImages() > 1) {
			    		NextWallpaper();
			    	}
			    }
			}
		};
		//Register the broadcast receiver that triggers when the lock screen is unlocked
		registerReceiver(xcvrUnlockScreen, new IntentFilter(Intent.ACTION_USER_PRESENT));
		
		//AutoWallpaper Service startup notification
		mNManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
		final Notification msg = new Notification(R.drawable.ic_launcher,getText(R.string.service_start_notif_title), System.currentTimeMillis());
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, AutoWallpaperActivity.class), 0);
		msg.setLatestEventInfo(this, getText(R.string.service_start_notif_title), getText(R.string.service_start_notif), contentIntent);
		mNManager.notify(Common.AWSERVICE_NOTIFY_ID, msg);
		Log.d(TAG, "onCreate: Notification set.");

		//Start timer if there are > 1 images
		if (Core.getNumImages() > 1 && Core.getAutoChange()) {
			if(Core.getTimerInterval() == Common.INTERVAL_SYSSTART) {
				NextWallpaper();
			} else {
				if(Core.getTimerInterval() < 500) {
					setTimer(Core.getTimerInterval(), Core.getAutoChange());
				}
			}
		}
		Log.d(TAG, "onCreate: Timer value set and started.");
		Log.d(TAG, "onCreate: Done.");
	}
	
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.i(TAG, "Received start id " + startId + ": " + intent);
        // We want this service to continue running until it is explicitly
        // stopped, so return sticky.
        return START_STICKY;
    }
	
	@Override
	public void onDestroy() {
		super.onDestroy();
		Log.d(TAG, "onDestroy");
		mNManager.cancel(Common.AWSERVICE_NOTIFY_ID);
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		return mBinder;
	}

	public class LocalBinder extends Binder {
		AWService getService() {
			return AWService.this;
		}
	}

	// *********************************************************************
	// Timer worker class

	private class onTimerTick extends TimerTask {
		public void run() {
			if (Core.getAutoChange() && Core.getTimerInterval() < 9999) {
				tickCount++;
				if (tickCount >= Core.getTimerInterval()) {
					NextWallpaper();
					Log.v(TAG, "Timer Interval Reached...");
					tickCount = 0;
				} else {
					Log.v(TAG, "5min timer tick");
				}
			}
		}
	}

	// END Timer worker class
	// *********************************************************************

	// *********************************************************************
	// Properties

	public void setTimer(int interval, boolean active) {
		try {
			if (interval > 1000) {
				active = false;
				timer.cancel();
				return;
			} // Non-time related intervals
			if (interval < 1) {
				interval = 6;
			}
			if (tickCount >= interval) {
				NextWallpaper();
				Log.v(TAG, "New timer interval caused a wallpaper change.");
			}
			tickCount = 0;
			if (active) {
				timer.scheduleAtFixedRate(new onTimerTick(), 200, 300000);
			} // Start the timer
			Core.setTimerInterval(interval);
			Core.setAutoChange(active);
			
		} catch (Exception e) {
			Log.e(TAG, "Error in setTimer", e);
		}
	}

	// END Properties Functions
	// *********************************************************************

	
	public void forceWallpaper(String file) throws FileNotFoundException {
		Core.SetWallpaper(new File(file));
	}
	
	public String NextWallpaper() {
		List<String> imagelist = Core.getAllImages();
		int numimages = imagelist.size(); int rnd;
		if(numimages < 2) { return null; }
		Log.v(TAG, "NexWallpaper:numimages = " + String.valueOf(numimages));
		rnd = (int) (Math.random() * ((numimages - 1) + 1));
		if(imagelist.get(rnd) == Core.getCurImg()) {
			rnd = (int) (Math.random() * ((numimages - 1) + 1));
			if(imagelist.get(rnd) == Core.getCurImg()) {
				rnd = (int) (Math.random() * ((numimages - 1) + 1));
			}
		}
		if (!Core.ValidateImage(imagelist.get(rnd)) ){
			Log.w(TAG, "NextWallpaper: Chosen image is invalid, trying again...");
			int rnd2 = (int) (Math.random() * ((numimages - 1) + 1));
			if (!Core.ValidateImage(imagelist.get(rnd2))) {
				Log.w(TAG, "NextWallpaper: Chosen image is invalid, AGAIN. Re-validating images in database...");
				Core.ValidateDBImages(imagelist);
				return null;
			}
		}
		File wp = new File(imagelist.get(rnd));
		Log.v(TAG, "NexWallpaper:rnd = " + String.valueOf(rnd));
		Log.v(TAG, "NexWallpaper:wp = " + wp.getAbsolutePath().toString());
		try {
			Core.SetWallpaper(wp);
		} catch (Exception e) {
			Log.e(TAG, "File not found when executing SetWallpaper()");
			e.printStackTrace();
		}
		String res = wp.getAbsoluteFile().toString();
		Core.setCurImg(res);
		return res;
	}
/*
	public void SetWallpaper(final File f) throws FileNotFoundException {
		WM = WallpaperManager.getInstance(this);
		final InputStream IS = new FileInputStream(f);		// if(set.getString(Common.CNF_WPMODE, "center") == "center") {
		
		Thread BasicSetImageThread = new Thread(new Runnable() {
			Bitmap image = BitmapFactory.decodeFile(f.getAbsolutePath().toString());

			@Override
			public void run() {
				try {
					Log.d("SetWallpaper", "Thread started!");
					if (Core.getWPMode() == "center") {
						Log.d("SetWallpaper", "Entered 'center' code block");
						WM.setStream(IS);
						IS.close();
					} else if (Core.getWPMode() == "fit_xy") {
						Log.d("SetWallpaper", "Entered 'fit_xy' code block");
						WM.setBitmap(generateBitmap(AWService.this
								.getBaseContext(), image = BitmapFactory
								.decodeStream(IS), WM.getDesiredMinimumWidth(),
								WM.getDesiredMinimumHeight()));
					} else if (Core.getWPMode().contains("scale_y")) {
						Log.d("SetWallpaper", "Entered 'scale_y' code block");
						float ratio = image.getWidth() / image.getHeight();
						int newWidth = (int) Math.round(image.getHeight()
								* ratio);
						WM.setBitmap(image = Bitmap.createScaledBitmap(image,
								newWidth, WM.getDesiredMinimumHeight(), true));
					} else if (Core.getWPMode() == "scale_x") {
						Log.d("SetWallpaper", "Entered 'scale_x' code block");
						float ratio = image.getWidth() / image.getHeight();
						int newHeight = (int) Math.round(image.getWidth()
								/ ratio);
						WM.setBitmap(image = Bitmap.createScaledBitmap(image,
								WM.getDesiredMinimumWidth(), newHeight, true));
					} else if (Core.getWPMode() == "scale_xy") {
						Log.d("SetWallpaper", "Entered 'scale_xy' code block");
						WM.setBitmap(image = Bitmap.createScaledBitmap(image,
								WM.getDesiredMinimumWidth(), WM
										.getDesiredMinimumHeight(), true));
					}
				} catch (IOException e) {
					Log.e(TAG, "An exception occured: " + e.getMessage());
					e.printStackTrace();
				}
				Log.d("SetWallpaper", "Thread finished!");
			}
		});
		//BasicSetImageThread.setPriority(3);
		BasicSetImageThread.start();
		Log.d("SetWallpaper", "Thread called...");
		}
	*/
		/*
		 * } else { Thread ScaleSetImageThread = new Thread(new Runnable() {
		 * 
		 * @Override public void run() { try { WM.setBitmap(scaledImage(f)); }
		 * catch (IOException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); } } public Bitmap scaledImage(File f) {
		 * InputStream imageIn; Bitmap image; try { imageIn = new
		 * FileInputStream(f); image = BitmapFactory.decodeStream(imageIn);
		 * if(set.getString(Common.CNF_WPMODE, "center") == "fit_y") { float
		 * ratio = image.getWidth() / image.getHeight(); int newWidth =
		 * (int)Math.round(image.getHeight() * ratio); image =
		 * Bitmap.createScaledBitmap(image, newWidth,
		 * WM.getDesiredMinimumHeight(), true); } else
		 * if(set.getString(Common.CNF_WPMODE, "center") == "fit_x") { float
		 * ratio = image.getWidth() / image.getHeight(); int newHeight =
		 * (int)Math.round(image.getWidth() / ratio); image =
		 * Bitmap.createScaledBitmap(image, WM.getDesiredMinimumWidth(),
		 * newHeight, true); } else if(set.getString(Common.CNF_WPMODE,
		 * "center") == "fit_xy") { image = Bitmap.createScaledBitmap(image,
		 * WM.getDesiredMinimumWidth(), WM.getDesiredMinimumHeight(), true); }
		 * return image; } catch (IOException e) {
		 * Log.e(TAG,"Could not open image " + f.getAbsolutePath().toString(),
		 * e); } return null; } }); ScaleSetImageThread.setPriority(8);
		 * ScaleSetImageThread.start(); }
		 */

	/*
	 * public void setBitmap(Bitmap bitmap) throws IOException { try { try {
	 * FileOutputStream fos = new FileOutputStream(new File());
	 * bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos); } finally { if (fos
	 * != null) { fos.close(); } } } catch (RemoteException e) { } }
	 */

	/*
	static Bitmap generateBitmap(Context context, Bitmap bm, int width,
			int height) {
		if (bm == null) {
			return bm;
		}
		bm.setDensity(DisplayMetrics.DENSITY_MEDIUM);

		// This is the final bitmap we want to return.
		// XXX We should get the pixel depth from the system (to match the
		// physical display depth), when there is a way.
		Bitmap newbm = Bitmap
				.createBitmap(width, height, Bitmap.Config.RGB_565);
		newbm.setDensity(DisplayMetrics.DENSITY_MEDIUM);
		Canvas c = new Canvas(newbm);
		c.setDensity(DisplayMetrics.DENSITY_MEDIUM);
		Rect targetRect = new Rect();
		targetRect.left = targetRect.top = 0;
		targetRect.right = bm.getWidth();
		targetRect.bottom = bm.getHeight();

		int deltaw = width - targetRect.right;
		int deltah = height - targetRect.bottom;

		if (deltaw > 0 || deltah > 0) {
			// We need to scale up so it covers the entire
			// area.
			float scale = 1.0f;
			if (deltaw > deltah) {
				scale = width / (float) targetRect.right;
			} else {
				scale = height / (float) targetRect.bottom;
			}
			targetRect.right = (int) (targetRect.right * scale);
			targetRect.bottom = (int) (targetRect.bottom * scale);
			deltaw = width - targetRect.right;
			deltah = height - targetRect.bottom;
		}

		targetRect.offset(deltaw / 2, deltah / 2);
		Paint paint = new Paint();
		paint.setFilterBitmap(true);
		paint.setDither(true);
		c.drawBitmap(bm, null, targetRect, paint);

		bm.recycle();
		return newbm;
	}
	*/
}
